#ifndef BAIDU_SPEECH_H
#define BAIDU_SPEECH_H

#include <Arduino.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <base64.h>

class BaiduSpeech {
private:
    String apiKey;      // API Key
    String secretKey;   // Secret Key
    String accessToken; // 访问令牌
    unsigned long tokenExpireTime; // 令牌过期时间（毫秒）
    
    // 获取访问令牌
    bool getAccessToken() {
        if (apiKey.length() == 0 || secretKey.length() == 0) {
            Serial.println("API Key或Secret Key不能为空");
            return false;
        }
        
        HTTPClient http;
        String tokenUrl = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=" + apiKey + "&client_secret=" + secretKey;
        
        http.begin(tokenUrl);
        int httpCode = http.GET();
        
        if (httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            DynamicJsonDocument doc(1024);
            DeserializationError error = deserializeJson(doc, payload);
            
            if (!error) {
                accessToken = doc["access_token"].as<String>();
                // 令牌有效期通常为30天，这里设置为29天以确保安全
                tokenExpireTime = millis() + 29 * 24 * 60 * 60 * 1000;
                Serial.println("获取访问令牌成功: " + accessToken);
                http.end();
                return true;
            } else {
                Serial.println("解析访问令牌JSON失败");
            }
        } else {
            Serial.printf("获取访问令牌失败，HTTP错误: %d\n", httpCode);
        }
        
        http.end();
        return false;
    }
    
    // 检查令牌是否有效，如果无效则重新获取
    bool ensureValidToken() {
        if (accessToken.length() == 0 || millis() > tokenExpireTime) {
            return getAccessToken();
        }
        return true;
    }

public:
    BaiduSpeech(String apiKey, String secretKey) : apiKey(apiKey), secretKey(secretKey), tokenExpireTime(0) {
        // 构造函数
    }
    
    // 初始化并获取访问令牌
    bool init() {
        return getAccessToken();
    }
    
    // 语音识别函数
    String speechToText(const uint8_t* audioData, size_t audioSize) {
        if (!ensureValidToken()) {
            return "获取访问令牌失败";
        }
        
        // 打印当前内存状态
        Serial.printf("语音识别前可用堆内存: %d 字节\n", ESP.getFreeHeap());
        
        // 检查音频大小是否合理
        if (audioSize > 100000) { // 限制音频大小为100KB
            Serial.println("音频数据过大，截断处理");
            audioSize = 100000;
        }
        
        // 将音频数据转换为Base64编码，使用分块处理减少内存使用
        const size_t chunkSize = 512; // 减小每次处理的数据块大小
        String base64Audio = "";
        size_t processedSize = 0;
        
        for (size_t i = 0; i < audioSize; i += chunkSize) {
            // 检查剩余内存
            if (ESP.getFreeHeap() < 10000) { // 提高内存阈值
                Serial.println("内存不足，停止处理");
                // 如果处理的数据不足原始数据的50%，则返回错误
                if (processedSize < audioSize / 2) {
                    return "内存不足，无法完成语音识别";
                }
                // 更新实际处理的数据大小
                audioSize = processedSize;
                break;
            }
            
            size_t currentChunkSize = min(chunkSize, audioSize - i);
            String chunk = base64::encode(audioData + i, currentChunkSize);
            
            // 验证编码结果
            if (chunk.length() == 0) {
                Serial.println("Base64编码失败");
                return "Base64编码失败";
            }
            
            base64Audio += chunk;
            processedSize += currentChunkSize;
            
            // 每处理4KB数据后检查内存
            if (processedSize % 4096 == 0) {
                Serial.printf("已编码 %d/%d 字节，可用内存: %d 字节\n", processedSize, audioSize, ESP.getFreeHeap());
            }
        }

        Serial.println("============================");
        Serial.println("speech:" + base64Audio);
        Serial.println(audioSize);
        
        HTTPClient http;
        String apiUrl = "https://vop.baidu.com/server_api";
        
        http.begin(apiUrl);
        http.addHeader("Content-Type", "application/json");
        
        // 构建请求体，减小JSON文档大小
        DynamicJsonDocument doc(8192); // 减小文档大小
        doc["format"] = "pcm"; // PCM格式
        doc["rate"] = 16000;    // 采样率
        doc["channel"] = 1;     // 单声道
        doc["token"] = accessToken;
        doc["cuid"] = "ESP32Device";
        doc["len"] = audioSize;
        doc["speech"] = base64Audio;
        
        String requestBody;
        serializeJson(doc, requestBody);
        
        int httpCode = http.POST(requestBody);
        String result = "";
        
        if (httpCode == HTTP_CODE_OK) {
            String payload = http.getString();
            DynamicJsonDocument resDoc(4096); // 减小文档大小
            DeserializationError error = deserializeJson(resDoc, payload);
            
            if (!error) {
                // 检查识别结果
                if (resDoc["err_no"] == 0) {
                    result = resDoc["result"][0].as<String>();
                } else {
                    result = "识别错误: " + String(resDoc["err_no"].as<int>()) + ", " + resDoc["err_msg"].as<String>();
                }
            } else {
                result = "解析识别结果JSON失败";
            }
        } else {
            result = "HTTP错误: " + String(httpCode);
        }
        
        // 打印处理后的内存状态
        Serial.printf("语音识别完成后可用堆内存: %d 字节\n", ESP.getFreeHeap());
        
        http.end();
        return result;
    }
};

#endif // BAIDU_SPEECH_H